using Newtonsoft.Json;
using System.Collections.Generic;
using System;
using System.IO;
using UnityEngine;
using UnityEngine.UI;
using UnityEditor;
using EditorTools;

namespace TRobot
{
    [Serializable]
    class IColor
    {
        public float r;
        public float g;
        public float b;
        public float a;
    }
    [Serializable]
    class ITextStyle
    {
        public string font;
        public float fontSize;
        public IColor color;
        public IColor strokeColor;
    }
    [Serializable]
    class ITextStyleRun
    {
        public int length;
        public ITextStyle style;
    }
    [Serializable]
    class IPrefabTextDetail
    {
        public string text;
        public ITextStyle style;
        public List<ITextStyleRun> styleRuns;
    }

    [Serializable]
    class IPrefabBaseNode
    {
        public string name;
    }
    
    [Serializable]
    class IPrefabInstruction : IPrefabBaseNode
    {
        public List<IPrefabNode> children;
    }

    [Serializable]
    class IPrefabNode : IPrefabBaseNode
    {
        public List<IPrefabNode> children;
        public string type;
        public float width;
        public float height;
        public float x;
        public float y;
        public IPrefabTextDetail text;
        public string image;
    }

    class PrefabGenerator
    {
        public void Make(string instructionFile) 
        {
            string fileContent = File.ReadAllText(instructionFile);
            var instruction = JsonConvert.DeserializeObject<IPrefabInstruction>(fileContent);
            // var instruction = JsonUtility.FromJson<IPrefabInstruction>(fileContent);
            GameObject prefab = MakeGameObject(instruction);
            var rt = prefab.GetComponent<RectTransform>();
            PrefabLayout.SetStrechStrech(rt, 0, 0, 0, 0);
            foreach (var child in instruction.children)
            {
                GameObject childObj = MakeNode(prefab.transform, child);
            }
            string prefabPath = Path.Combine("Assets/AssetSources/ui/system", instruction.name + ".prefab");
            bool success;
            PrefabUtility.SaveAsPrefabAsset(prefab, prefabPath, out success);
            GameObject.DestroyImmediate(prefab);
            if (success)
            {
                Debug.LogFormat("[Psd2Prefab] {0} generated.", prefabPath);
            }
        }

        private GameObject MakeNode(Transform parent, IPrefabNode node)
        {
            GameObject obj = MakeGameObject(node);
            var rt = obj.GetComponent<RectTransform>();
            rt.SetParent(parent);
            rt.sizeDelta = new Vector2(node.width, node.height);
            rt.anchoredPosition = new Vector2(node.x, node.y);
            if (node.type == "Text")
            {
                AddText(obj, node.text);
            }
            else if (node.type == "Image")
            {
                AddImage(obj, node.image);
            }

            foreach (var child in node.children)
            {
                GameObject childObj = MakeNode(rt, child);
            }
            return obj;
        }

        private GameObject MakeGameObject(IPrefabBaseNode instruction)
        {
            GameObject obj = new GameObject();
            obj.name = instruction.name;
            obj.AddComponent<RectTransform>();
            return obj;
        }

        private void AddText(GameObject obj, IPrefabTextDetail detail)
        {
            var com = obj.AddComponent<Text>();
            com.raycastTarget = false;
            com.alignment = TextAnchor.UpperLeft;
            com.font = AssetDatabase.LoadAssetAtPath<Font>("Assets/AssetSources/font/normal.ttf");
            if (detail.style != null)
            {
                if (detail.style.color != null)
                {
                    com.color = ToColor(detail.style.color);
                }
                com.fontSize = Mathf.RoundToInt(detail.style.fontSize) - 1;
                if (null != detail.style.strokeColor)
                {
                    Shadow sd = obj.AddComponent<Shadow>();
                    sd.effectColor = ToColor(detail.style.strokeColor);
                    sd.effectDistance = new Vector2(1, 1);
                }
            }
            if (detail.styleRuns != null)
            {
                string formattedText = "";
                int startIndex = 0;
                foreach (var sr in detail.styleRuns)
                {
                    string textSlice = detail.text.Substring(startIndex, sr.length);
                    startIndex += sr.length;
                    if (sr.style.color != null)
                    {
                        textSlice = "<color=\"#" + ToHTMLColor(sr.style.color) + "\">" + textSlice + "</color>";
                    }
                    formattedText += textSlice;
                }
                com.supportRichText = true;
                com.text = formattedText;
            }
            else
            {
                com.supportRichText = false;
                com.text = detail.text;
            }
        }

        private void AddImage(GameObject obj, string imgPath)
        {
            var img = obj.AddComponent<Image>();
            img.type = Image.Type.Simple;
            var sprite = AssetDatabase.LoadAssetAtPath<Sprite>(imgPath);
            if (sprite == null)
            {
                Debug.LogErrorFormat("Load sprite failed: {0}", imgPath);
            }
            img.sprite = sprite;
        }
        public static Color ToColor(IColor c)
        {
            return new Color(c.r / 255, c.g / 255, c.b / 255, c.a);
        }
        public static string ToHTMLColor(IColor c)
        {
            return ColorUtility.ToHtmlStringRGB(ToColor(c));
        }
    }

    public class Psd2Prefab : EditorWindow
    {
        private string srcPath = "";
        private PathDragLabel srcLabel = new PathDragLabel();

        [MenuItem("Psd2Prefab/生成预制体")]
        public static void Test()
        {
            EditorWindow.GetWindow<Psd2Prefab>(false, "Psd2Prefab", true).Show();            
        }

        private void OnGUI()
        {
            PathDragLabel.Begin();
            
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("预制体描述json:", GUILayout.Width(150f));
            srcPath = srcLabel.Label(srcPath, "", 16);
            EditorGUILayout.EndHorizontal();

            PathDragLabel.End();

            if (GUILayout.Button("一键生成"))
            {
                var generator = new PrefabGenerator();
                generator.Make(srcPath);
            }
        }
    }
}